package com.zzedu.framework.lock.impl;

import com.zzedu.common.exception.ServiceException;
import com.zzedu.framework.lock.IDistributedLockService;
import com.zzedu.framework.web.exception.LockException;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Component
public class DistributedLockServiceImpl implements IDistributedLockService {
    Logger logger = LoggerFactory.getLogger(IDistributedLockService.class);
    @Autowired
    RedissonClient redissonClient;


    /**
     * @param lockName 锁名称
     * @param waitTime 等待时间
     * @param lockTime 锁有效期
     * @param timeUnit 时间单位
     * @return
     */
    @Override
    public RLock getLock(String lockName, Long waitTime, Long lockTime, TimeUnit timeUnit) {
        try {
            RLock lock = redissonClient.getLock(lockName);
            boolean lockResult = lock.tryLock(waitTime, lockTime, timeUnit);
            logger.info("lockName:{},lockResult:{}", lockName, lockResult);
            if (!lockResult) {
                throw new LockException("获取分布式锁异常");
            }
            return lock;
        } catch (InterruptedException ex) {
            throw new LockException("获取分布式锁异常");
        } catch (Exception e) {
            logger.error("获取分布式锁失败,lockName:{},详细:{}", lockName, e.getMessage());
            throw new ServiceException("服务器拥挤请稍后重试");
        }
    }

    @Override
    public <T> T executeWithLock(String lockName, Long waitTime, Long lockTime, TimeUnit timeUnit, Supplier<T> supplier) {
        RLock lock = null;
        try {
            lock = getLock(lockName, waitTime, lockTime, timeUnit);
            if (null != lock) {
                return supplier.get();
            }
            throw new LockException("获取分布式锁异常");
        } catch (Exception e) {
            logger.error("执行excuteWithoutLock 失败 详细:{}", lockName, e.getMessage());
            throw e;
        } finally {
            if (null != lock) {
                //释放锁
                logger.info("开始释放锁:{}", lockName);
                lock.unlock();
            }
        }
    }
}
